package com.xjscrm.console.common.web;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.xjscrm.common.constant.CacheKey;
import com.xjscrm.common.constant.ResponseMsg;
import com.xjscrm.common.entity.MerchatChild;
import com.xjscrm.common.entity.MerchatChildmerchatRelation;
import com.xjscrm.common.entity.SysMenu;
import com.xjscrm.common.entity.SysRole;
import com.xjscrm.common.result.ResponseCode;
import com.xjscrm.common.result.ResponseResult;
import com.xjscrm.common.utils.HttpServletResponseUtil;
import com.xjscrm.common.utils.JsonUtils;
import com.xjscrm.common.utils.Tools;
import com.xjscrm.console.common.util.LoginContext;
import com.xjscrm.console.common.util.RouteDataProcessorUtil;
import com.xjscrm.console.entity.Route;
import com.xjscrm.console.param.menu.SysMenuInfoDto;
import com.xjscrm.console.service.common.menu.MenuService;
import com.xjscrm.console.service.common.user.UserService;
import com.xjscrm.console.service.customer.childUser.ChildMerchatService;
import com.xjscrm.console.service.customer.role.RoleService;
import com.xjscrm.console.vo.LoginVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyInterceptor extends HandlerInterceptorAdapter {

    private static Logger logger= LoggerFactory.getLogger(MyInterceptor.class);

    @Value("#{'${exclude.token}'.replaceAll('\\s*', '').split(',')}")
    private List<String> excludeToken;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    @Autowired
    private MenuService menuService;

    @Autowired
    private ChildMerchatService childMerchatService;

    @Autowired
    private RoleService roleService;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String path = request.getServletPath();
        String token = request.getHeader("Auth-Token");

        if (!excludeToken.contains(path)) {
            Map entries = redisTemplate.opsForHash().entries(String.format(CacheKey.AUTH_TOKEN,token));
            logger.info("login user is:{},url is:{}", new Object[]{entries != null ? redisTemplate.opsForHash().get(String.format(CacheKey.AUTH_TOKEN,token),"id") : null, path});
            if (entries == null ||entries.isEmpty()) {
                HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.NOT_LOGIN, ResponseMsg.NOT_LOGIN));
                return false;
            }
            LoginVO loginVO = BeanUtil.mapToBean(entries, LoginVO.class, true);
            LoginContext.setLogin(loginVO);


            String appKey = Tools.getStr(request.getHeader("appKey"));
            if (StringUtils.isNotBlank(appKey)) {
                SysMenuInfoDto sysMenuInfoDto = new SysMenuInfoDto();
                sysMenuInfoDto.setAppKey(appKey);
                SysMenu sysMenu = menuService.selectByAppKey(sysMenuInfoDto);
                if (sysMenu != null && StringUtils.isNotBlank(sysMenu.getRoutes())) {
                    try {
                        List<Route> routeList = JSONObject.parseArray(sysMenu.getRoutes(), Route.class);
                        Map<String, String> analysis = RouteDataProcessorUtil.analysis(routeList);
                        String fullPath = request.getContextPath() + path;
                        if (analysis.containsKey(fullPath)) {
                            String menu_auth = analysis.get(fullPath);
                            //取出此API所属的模块pKey
                            if (loginVO.getType() != null && loginVO.getType() == 1) {
                                //验证菜单权限
                                String auth = Tools.getStr(request.getHeader("auth"));
                                //访问权限中的API时，必须带有auth参数
                                if (StringUtils.isBlank(auth)) {
                                    HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.NOT_PERMISSION, "子帐单访问必须带有菜单权限auth参数"));
                                    return false;
                                }
                                if (!menu_auth.equals(auth)) {
                                    HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.NOT_PERMISSION, "权限auth不匹配"));
                                    return false;
                                }

                                //验证子账号所在角色是否具有访问该接口权限
                                MerchatChild merchatChild = childMerchatService.getById(loginVO.getMerId(), loginVO.getId());
                                if (merchatChild == null) {
                                    HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.NOT_PERMISSION, "该子账号不存在"));
                                    return false;
                                }
                                SysRole sysRole = roleService.selectById(merchatChild.getRoleId(), loginVO.getMerId());
                                if (sysRole == null || StringUtils.isBlank(sysRole.getAuthData())) {
                                    HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.NOT_PERMISSION, "该子账号未配置权限"));
                                }

                                try {
                                    JSONObject jsonObject = JSONObject.parseObject(sysRole.getAuthData());
                                    List<String> authList = JSONObject.parseArray(jsonObject.getString(appKey), String.class);
                                    if (!authList.contains(auth)) {
                                        HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.NOT_PERMISSION, "该子账号未配置该菜单权限"));
                                    }
                                } catch (Exception e) {
                                    HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.NOT_PERMISSION, "子账号所在角色权限数据出错"));
                                }
                            }
                        }
                    } catch (Exception e) {
                        HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.NOT_PERMISSION, "没有权限访问"));
                        return false;
                    }
                }
            } else {
                //子账号必须带appKey参数
                if (loginVO.getType() != null && loginVO.getType() == 1) {
                    HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.PARAMETER_EXCEPTION, "子账号访问系统时，需要带appKey参数"));
                    return false;
                }
            }







            if(request instanceof CustomHttpServletRequestWrapper) { //JONS增加参数
                CustomHttpServletRequestWrapper requestWrapper = (CustomHttpServletRequestWrapper) request;
                String body = requestWrapper.getBody();
                JSONObject param = null;
                if(StringUtils.isNotBlank(body)){
                    try {
                        param = JSONObject.parseObject(body);
                    }catch (Exception e){
                    }
                }
                if(param == null){
                    param = new JSONObject();
                }
                param.put("merId", loginVO.getMerId());
                param.put("operatorType",loginVO.getType());
                if(loginVO.getTenantId()!=null){
                    param.put("tenantId",loginVO.getTenantId());
                }
                if(loginVO.getType()!=null&&loginVO.getType()==1){
                    param.put("childId",loginVO.getId());
                }
                //对参数前后去空
                param = JsonUtils.jsonTrim(param);
                requestWrapper.setBody(param.toJSONString());
            }else if(request instanceof RequestParameterWrapper){ //Parameter增加参数
                RequestParameterWrapper requestWrapper = (RequestParameterWrapper) request;
                Map<String, Object> extraParams = new HashMap<>();
                extraParams.put("merId", loginVO.getMerId());
                extraParams.put("operatorType",loginVO.getType());
                if(loginVO.getTenantId()!=null){
                    extraParams.put("tenantId", loginVO.getTenantId());
                }
                if(loginVO.getType()!=null&&loginVO.getType()==1){
                    extraParams.put("childId",loginVO.getId());
                }
                requestWrapper.addParameters(extraParams);
            }else if(request instanceof StandardMultipartHttpServletRequest){ //上传文件
                StandardMultipartHttpServletRequest requestWrapper = (StandardMultipartHttpServletRequest) request;
                requestWrapper.setAttribute("merId", loginVO.getMerId());
                requestWrapper.setAttribute("operatorType",loginVO.getType());
                if(loginVO.getTenantId()!=null){
                    requestWrapper.setAttribute("tenantId", loginVO.getTenantId());
                }
                if(loginVO.getType()!=null&&loginVO.getType()==1){
                    requestWrapper.setAttribute("childId",loginVO.getId());
                }
            }
//            else {
//                HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.PARAMETER_EXCEPTION, "请求数据格式有误"));
//                return false;
//            }
        }

        //  子账号登录，写入merId
        if("/login/childLoginByPwd".equals(path)){
            Long merId=null;
            CustomHttpServletRequestWrapper requestWrapper = (CustomHttpServletRequestWrapper) request;
            String body = requestWrapper.getBody();
            JSONObject param = null;
            if(StringUtils.isNotBlank(body)){
                try {
                    param = JSONObject.parseObject(body);
                }catch (Exception e){
                    HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.PARAMETER_EXCEPTION, "请求数据有误"));
                    return false;
                }
            }else {
                HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.PARAMETER_EXCEPTION, "请求数据有误"));
                return false;
            }

            String userAccount = param.get("userAccount").toString();
            merId = (Long) redisTemplate.opsForValue().get(String.format(CacheKey.MERCHAT_CHILEMERCHST_RELATION, userAccount));
            if(merId==null){
                //如果缓存丢失，到数据库中查询
                MerchatChildmerchatRelation merchatChildmerchatRelationByUserAccount = userService.getMerchatChildmerchatRelationByUserAccount(userAccount);
                if (merchatChildmerchatRelationByUserAccount==null){
                    HttpServletResponseUtil.print(response, new ResponseResult(ResponseCode.PARAMETER_EXCEPTION, "未找到子账号对应的商户"));
                    return false;
                }
                merId=merchatChildmerchatRelationByUserAccount.getMerId();
                //将子账号和运营商账号存到redis
                redisTemplate.opsForValue().set(String.format(CacheKey.MERCHAT_CHILEMERCHST_RELATION,userAccount),merId);
            }
            //将商户ID写入参数
            param.put("merId", merId);
            //对参数前后去空
            param = JsonUtils.jsonTrim(param);
            requestWrapper.setBody(param.toJSONString());

        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        LoginContext.delLogin();
    }
}